package com.seo.service.redis.impl;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import com.seo.constants.RedisConstant;
import com.seo.redis.conf.RedisConf;
import com.seo.service.redis.JedisUtil;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * jedis服务
 *
 * @author joe
 * @version 2018.01.09 14:36
 */
@Service
@EnableConfigurationProperties(RedisConf.class)
public class JedisService implements JedisUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(JedisUtil.class);

	/*
	 * @Autowired private JedisCluster jedisCluster;
	 */

	@Autowired
	private JedisPool jedisPool; // 注入JedisPool

	/**
	 * 生成poolConfig
	 *
	 * @param redisConf
	 *            redis配置
	 * @return poolConfig
	 */
	@Bean("poolConfig")
	public GenericObjectPoolConfig poolConfig(RedisConf redisConf) {
		LOGGER.debug("redis配置为：" + redisConf);
		GenericObjectPoolConfig config = new GenericObjectPoolConfig();
		config.setMaxIdle(redisConf.getMaxIdle());
		config.setMaxWaitMillis(redisConf.getMaxWait());
		config.setTestOnBorrow(redisConf.isTestOnBorrow());
		config.setMaxTotal(redisConf.getMaxTotal());
		config.setMinIdle(redisConf.getMinIdle());
		return config;
	}

	/**
	 * 生成jedisPool
	 *
	 * @param config
	 *            jedis pool配置
	 * @param redisConf
	 *            redis配置
	 * @return jedisPool
	 */
	@Bean("jedisPool")
	public JedisPool jedisPool(@Autowired GenericObjectPoolConfig config, RedisConf redisConf) {

		if (StringUtils.isEmpty(redisConf.getPassword())) {
			return new JedisPool(config, redisConf.getHost(), redisConf.getPort(), redisConf.getTimeout());
		} else {
			return new JedisPool(config, redisConf.getHost(), redisConf.getPort(), redisConf.getTimeout(),
					redisConf.getPassword());
		}
	}

	@Override
	public boolean lock(String key, long timeout, int expire) {
		Jedis jedis = getRedis();
		long nanoTime = System.nanoTime();
		timeout = nanoTime + timeout * RedisConstant.MILLI_NANO_TIME;
		try {
			
			while (System.nanoTime() < timeout) {
				if (jedis.setnx(key, key) == 1) {
					jedis.expire(key, expire);
					return true;
				}
				LOGGER.info("出现锁等待:" + key);
				Thread.sleep(200);
			}
			return false;
		} catch (Exception e) {
			LOGGER.info("获取锁错误" + key);
			return false;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public boolean lockByTime(String key, int time, int expire) {
		Jedis jedis = getRedis();
		try {
			int num = 1;
			while (num <= time) {
				if (jedis.setnx(key, key) == 1) {
					jedis.expire(key, expire);
					return true;
				}
				num++;
				LOGGER.info("出现锁等待:" + key);
				Thread.sleep(200);
			}
			return false;
		} catch (Exception e) {
			LOGGER.info("获取锁错误" + key);
			return false;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public void unlock(String key) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			jedis.del(key);
		} catch (Exception e) {
			LOGGER.info("删除锁错误" + key);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}

	}

	@Override
	public String get(String key) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.get(key);
		} catch (Exception e) {
			LOGGER.info("获取redis值" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}

	}

	@Override
	public void set(String key, String value) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			jedis.set(key, value);
		} catch (Exception e) {
			LOGGER.info("设置redis值" + key);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public void set(String key, String value, int expire) {

		Jedis jedis = null;
		try {
			jedis = getRedis();
			jedis.set(key, value);
			jedis.expire(key, expire);
		} catch (Exception e) {
			LOGGER.info("设置redis值" + key);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public Jedis getRedis() {
		return jedisPool.getResource();
	}

	@Override
	public void del(String key) {

		Jedis jedis = null;
		try {
			jedis = getRedis();
			getRedis().del(key);
		} catch (Exception e) {
			LOGGER.info("删除redis值" + key);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}

	}

	@Override
	public void expire(String key, int expire) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			jedis.expire(key, expire);
		} catch (Exception e) {
			LOGGER.info("设置失效时间redis值" + key);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public boolean exists(String key) throws Exception {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.exists(key);
		} catch (Exception e) {
			LOGGER.info("检查redis值" + key);
			throw new Exception(e);
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public Map<String, String> hgetAll(String key) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.hgetAll(key);
		} catch (Exception e) {
			LOGGER.info("获取HMAP集合" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public Long hdel(String key, String... fields) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.hdel(key, fields);
		} catch (Exception e) {
			LOGGER.info("删除MAP中的子值" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public Long hset(String key, String field, String value) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.hset(key, field, value);
		} catch (Exception e) {
			LOGGER.info("设置值HMAP" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public Long rpush(String key, String value) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.rpush(key, value);
		} catch (Exception e) {
			LOGGER.info("设置值list" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}
	
	@Override
	public Long lpush(String key, String value) {
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.lpush(key, value);
		} catch (Exception e) {
			LOGGER.info("设置值list" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
	}

	@Override
	public List<String> blpop(int timeout, String key){
		Jedis jedis = null;
		try {
			jedis = getRedis();
			return jedis.blpop(timeout, key);
		} catch (Exception e) {
			LOGGER.info("弹出并移除BLPOP" + key);
			return null;
		} finally {
			jedisPool.returnResourceObject(jedis);
		}
		
	}
}
